package cz.proks.easyhelpdesk.gwt.activity;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

import cz.proks.easyhelpdesk.api.model.Category;
import cz.proks.easyhelpdesk.api.model.Helpdesk;
import cz.proks.easyhelpdesk.api.model.HelpdeskMember;
import cz.proks.easyhelpdesk.api.model.HelpdeskRole;
import cz.proks.easyhelpdesk.api.model.User;
import cz.proks.easyhelpdesk.api.model.base.Id;
import cz.proks.easyhelpdesk.gwt.ClientFactory;
import cz.proks.easyhelpdesk.gwt.Globals;
import cz.proks.easyhelpdesk.gwt.activity.base.RestrictedHelpdeskActivity;
import cz.proks.easyhelpdesk.gwt.place.SettingsPlace;
import cz.proks.easyhelpdesk.gwt.restapi.CategoryRestApi;
import cz.proks.easyhelpdesk.gwt.restapi.HelpdeskMemberRestApi;
import cz.proks.easyhelpdesk.gwt.restapi.RestDomainCallback;
import cz.proks.easyhelpdesk.gwt.restapi.RestIdCallback;
import cz.proks.easyhelpdesk.gwt.restapi.ThreadMemberRestApi;
import cz.proks.easyhelpdesk.gwt.restapi.UserRestApi;
import cz.proks.easyhelpdesk.gwt.ui.SettingsView;
import cz.proks.easyhelpdesk.gwt.ui.base.RestrictedHelpdeskView;
import cz.proks.easyhelpdesk.gwt.utils.RestUtils;

public class SettingsActivity extends RestrictedHelpdeskActivity<SettingsPlace> implements SettingsView.Presenter {
    private SettingsView view;
    private Helpdesk currentHelpdesk;
    private final Collection<Category> categories;
    private final Map<User, Boolean> users;
    private final Collection<HelpdeskRole> helpdeskRoles;
    private final Map<User, HelpdeskRole> memberRoles;    

    public SettingsActivity(SettingsPlace place, ClientFactory clientFactory, PlaceHistoryMapper placeMapper) {
        super(place, clientFactory, placeMapper);

        this.view = clientFactory.getSettingsView();
        this.view.setPresenter(this);

        this.categories = new LinkedList<Category>();
        this.users = new LinkedHashMap<User, Boolean>();        
        this.helpdeskRoles = new LinkedList<HelpdeskRole>();
        this.memberRoles = new LinkedHashMap<User, HelpdeskRole>();
    }
    
    @Override
    protected boolean hasAccess() {        
        return super.hasAccess() && Globals.isHelpdeskOwner();
    }

    @Override
    protected RestrictedHelpdeskView getView() {
        return view;
    }

    @Override
    protected void onPermission(AcceptsOneWidget panel, EventBus eventBus) {
        clear();

        currentHelpdesk = Globals.getHelpdesk(getPlace().getHelpdeskId());

        categories.addAll(Globals.getCategoryMapFor(currentHelpdesk).values());        
        helpdeskRoles.addAll(Globals.getHelpdeskRolesFor(currentHelpdesk));
        users.putAll(getUsers());
        memberRoles.putAll(getMemberRoles());

        view.onErase();
        view.setCurrentHelpdesk(currentHelpdesk);
        view.setCategories(categories);
        view.setHelpdeskRoles(helpdeskRoles);
        view.setMembersRoles(memberRoles);
        view.setHelpdeskUsers(users);

        panel.setWidget(view);
    }

    @Override
    public void changeSettingsHeldpesk(Helpdesk helpdesk) {
        getClientFactory().getPlaceController().goTo(new SettingsPlace(helpdesk.getId()));
    }

    @Override
    public void saveCategory(final Category category) {
        new CategoryRestApi().create(category, new RestIdCallback() {

            @Override
            public void onIdSuccess(Id id) {
                category.setId(id.getId());

                categories.add(category);
                view.setCategories(categories);
                view.setAddCategoryLabel(null);

                Globals.getCategoryMapFor(currentHelpdesk).put(id.getId(), category);
            }
        });
    }

    @Override
    public void deleteCategory(final Category category) {
        new CategoryRestApi().remove(category.getId(), new RestUtils.Callback() {

            @Override
            public void onSuccess(JSONValue val) {
                categories.remove(category);
                view.setCategories(categories);

                Globals.getCategoryMapFor(currentHelpdesk).remove(category.getId());
            }
        });
    }

    @Override
    public void saveHelpdeskMember(final Helpdesk helpdesk, final User user, final HelpdeskRole role) {
        if (Globals.getHelpdeskMemberFor(currentHelpdesk, user) != null) {
            Window.alert(getClientFactory().getHelpdeskMessages().errorHelpdeskUserExist());
            return;
        }
        
        // check for user exist
        new UserRestApi().get(user.getId(), new RestDomainCallback<User>() {
            @Override
            public void onDomainSuccess(final User restUser) {
                if (restUser == null)  {
                    Window.alert(getClientFactory().getHelpdeskMessages().errorUserNotExist());
                    return;
                }
                
                // save helpdesk member
                final HelpdeskMember helpdeskMember = getHelpdeskMember(helpdesk, user, role);
                new HelpdeskMemberRestApi().create(helpdeskMember, new RestIdCallback() {

                    @Override
                    public void onIdSuccess(Id id) {
                        helpdeskMember.setId(id.getId());

                        // for operator role share other threads
                        if (getHeldpeskRoleFor(helpdeskMember) == HelpdeskRole.OPERATOR)
                            new ThreadMemberRestApi().shareForHelpdeskMemberAndRole(id.getId(), getHeldpeskRoleFor(helpdeskMember), new RestUtils.Callback() {

                                @Override
                                public void onSuccess(JSONValue val) {
                                    Globals.getHelpdeskMemberMapFor(currentHelpdesk).put(helpdeskMember.getId(), helpdeskMember);
                                    Globals.setUserFor(helpdeskMember, restUser);
                                    memberRoles.put(user, getHeldpeskRoleFor(helpdeskMember));
                                    view.setMembersRoles(memberRoles);
                                    view.setHelpdeskUsers(getUsers());   
                                    view.setAddMemberId(null);
                                        
                                }
                            });
                        else {
                            Globals.getHelpdeskMemberMapFor(currentHelpdesk).put(helpdeskMember.getId(), helpdeskMember);
                            Globals.setUserFor(helpdeskMember, restUser);
                            memberRoles.put(user, getHeldpeskRoleFor(helpdeskMember));
                            view.setMembersRoles(memberRoles);
                            view.setHelpdeskUsers(getUsers());
                            view.setAddMemberId(null);
                        }

                    }
                });
            }
        });
    }

    @Override
    public void deleteHelpdeskMember(final Helpdesk helpdesk, final User user) {
        final HelpdeskMember helpdeskMember = Globals.getHelpdeskMemberFor(currentHelpdesk, user);

        
        
        new HelpdeskMemberRestApi().remove(helpdeskMember.getId(), new RestUtils.Callback() {

            @Override
            public void onSuccess(JSONValue val) {
                Globals.getHelpdeskMemberMapFor(currentHelpdesk).remove(helpdeskMember.getId());
                view.setHelpdeskUsers(getUsers());
            }
        });
    }

    @Override
    public void updateMemberRole(final User user, final HelpdeskRole role) {
        HelpdeskMember helpdeskMember = Globals.getHelpdeskMemberFor(currentHelpdesk, user);
        setHelpdeskRoleFor(helpdeskMember, role);

        new HelpdeskMemberRestApi().update(helpdeskMember, new RestUtils.Callback() {

            @Override
            public void onSuccess(JSONValue val) {
                memberRoles.put(user, role);
                view.setMembersRoles(memberRoles);
                view.setHelpdeskUsers(getUsers());
            }
        });
    }

    private void clear() {
        this.categories.clear();
        this.users.clear();        
        this.helpdeskRoles.clear();
        this.memberRoles.clear();
    }

    private HelpdeskRole getHeldpeskRoleFor(HelpdeskMember helpdeskMember) {
        return helpdeskMember.getHelpdeskRoles().get(0);
    }

    private Map<User, HelpdeskRole> getMemberRoles() {
        Map<User, HelpdeskRole> map = new LinkedHashMap<User, HelpdeskRole>();

        for (User user : users.keySet()) {
            HelpdeskMember helpdeskMember = Globals.getHelpdeskMemberFor(currentHelpdesk, user);
            map.put(user, helpdeskMember.getHelpdeskRoles().get(0));
        }

        return map;
    }

    private Map<User, Boolean> getUsers() {
        Map<User, Boolean> users = new LinkedHashMap<User, Boolean>();

        Collection<HelpdeskMember> helpdeskMembers = Globals.getHelpdeskMemberMapFor(currentHelpdesk).values();

        for (HelpdeskMember helpdeskMember : helpdeskMembers) {
            User user = Globals.getUserFor(helpdeskMember);
            users.put(user, !Globals.isHelpdeskOwner(user, currentHelpdesk));
        }

        return users;
    }

    private HelpdeskMember getHelpdeskMember(Helpdesk helpdesk, User user, HelpdeskRole helpdeskRole) {
        HelpdeskMember helpdeskMember = new HelpdeskMember();
        List<HelpdeskRole> roles = new LinkedList<HelpdeskRole>();

        roles.add(helpdeskRole);

        helpdeskMember.setHelpdeskId(helpdesk.getId());
        helpdeskMember.setUserId(user.getId());
        helpdeskMember.setHelpdeskRoles(roles);

        return helpdeskMember;
    }

    private void setHelpdeskRoleFor(HelpdeskMember helpdeskMember, HelpdeskRole role) {
        helpdeskMember.getHelpdeskRoles().clear();
        helpdeskMember.getHelpdeskRoles().add(role);
    }
}